﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Core
{
    /// <summary>
    /// 映射扩展
    /// </summary>
    public static class MapperExtensions
    {
        #region AsMergeObject
        /// <summary>
        /// 合并对象
        /// TODO: 数据合并不是特别好用,待改进
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="dts"></param>
        /// <param name="src"></param>
        /// <param name="ignoreProperties"></param>
        /// <returns></returns>
        public static TModel AsMergeObject<TModel>(this TModel dts, TModel src, params string[] ignoreProperties)
        {
            var jsonSerializer = new Newtonsoft.Json.JsonSerializer { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore };
            var JToken1 = JToken.FromObject(src, jsonSerializer);
            var JToken2 = JToken.FromObject(dts, jsonSerializer);

            RecursivelyChangeJtokenSubPropertiesValue(JToken1, JToken2, ignoreProperties);

            return JToken2.ToObject<TModel>();
        }

        private static void RecursivelyChangeJtokenSubPropertiesValue(JToken src, JToken dts, string[] ignoreProperties)
        {
            if (src.Type == JTokenType.Array)
            {
                if (dts.SelectToken(src.Path) as JArray == null)
                    dts.SelectToken(src.Path).Replace(src);
                else
                {
                    foreach (var item in src as JArray)
                    {
                        if (ignoreProperties.Contains(item.Path)) continue;

                        if (item.Children().Count() == 0 && item.Type != JTokenType.Null)
                            dts.SelectToken(item.Path).Replace(item.Value<Object>() as JToken);
                        else
                            RecursivelyChangeJtokenSubPropertiesValue(item, dts, ignoreProperties);

                    }
                }
            }
            else
            {
                // 当字段属性为Array时自动进行全量替换处理
                if (!string.IsNullOrWhiteSpace(src.Path) && dts.SelectToken(src.Path) is JArray replaceToken)
                {
                    replaceToken.Parent?.Replace(src);
                    return;
                }

                // 常规字段处理
                foreach (var item in src.Children())
                {
                    if (ignoreProperties.Contains(item.Path)) continue;

                    if (item.Children().Count() == 0 && item.Type != JTokenType.Null)
                        dts.SelectToken(item.Path).Replace(item.Value<Object>() as JToken);
                    else if (dts.SelectToken(item.Path) != null)
                        RecursivelyChangeJtokenSubPropertiesValue(item, dts, ignoreProperties);
                    else
                        dts.SelectToken(src.Path).Replace(src);
                }
            }
        } 
        #endregion
    }
}
